#ifndef CONSTRUCT_DEF_HPP
#define CONSTRUCT_DEF_HPP

/**
 *  实现两个方法：
 *  1. construct 正确调用调用T的构造器
 *  2. destroy   正确调用T的析构器
 */

#include "iterator.hpp"
#include <new>

namespace TingSTL {
// /////////////////////////  构造对象 /////////////////////////

// 在 p 构造对象 , 无参构造  placement new (调用构造的一种写法)
template <typename T>
void construct(T *p) {
    ::new ((void *)p) T();
}

// 有参数构造 声明类型 ... 在前，解包... 在后
template <typename T, typename... Args>
void construct(T *p, Args &&...args) {
    ::new ((void *)p) T(std::forward<Args>(args)...);
}

// /////////////////////////  析构对象 /////////////////////////

/**
 * https://cplusplus.com/reference/type_traits/is_trivially_destructible/
 * is_trivially_destructible 检测 类型是否是 可破坏的 ， true 无需单独调用析构
 * ， false 得单独调用析构 ，
 */

template <typename T>
void destroy(T *p) {
    if (p == nullptr)
        return;
    PrivateTingSTL::_destroy_once(p, std::is_trivially_destructible<T>{});
}

// 针对 迭代器版本, 必须是 forward iter
template <typename ForwardIter>
void destroy(ForwardIter first, ForwardIter last) {
    static_assert(is_forward_iterator<ForwardIter>::value,
                  "destroy_multiple need ForwardIter");
    PrivateTingSTL::_destroy_multiple(
        first, last,
        std::is_trivially_destructible<
            typename iterator_traits<ForwardIter>::value_type>{});
}

// ////////////////////////////////////////// 不对外暴露私有方法
// //////////////////////////
namespace PrivateTingSTL {
// 针对没有 析构函数的类型 进行重载
template <typename T>
void _destroy_once(T *p, std::true_type) {
}

// 有析构函数的类型 调用 析构函数
template <typename T>
void _destroy_once(T *p, std::false_type) {
    p->~T();
}

template <typename ForwardIter>
void _destroy_multiple(ForwardIter first, ForwardIter last,
                       std::true_type) {
}

template <typename ForwardIter>
void _destroy_multiple(ForwardIter first, ForwardIter last,
                       std::false_type) {
    using T = typename iterator_traits<ForwardIter>::value_type;
    while (first != last) {
        (&*first)->~T();
        ++first;
    }
}
} // namespace PrivateTingSTL

} // namespace TingSTL

#endif // CONSTRUCT_DEF_HPP